/*  Copyright (c) 2011, Philip Busch <vzxwco@gmail.com>
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */


#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include "irc.h"

/** Creates an irc_server_msg object. */
irc_server_msg *irc_server_msg_create()
{
	irc_server_msg *msg;
	size_t i;

	msg = malloc(sizeof(*msg));

	if (msg) {
		msg->prefix = NULL;
		msg->command = NULL;
		msg->trailing = NULL;

		for (i = 0; i < IRC_MAX_PARAMS; i++)
			msg->params[i] = NULL;
	}

	return msg;
}

/** Frees an irc_server_msg object. */
void irc_server_msg_free(irc_server_msg *msg)
{
	size_t i;

	free(msg->prefix);
	free(msg->command);
	free(msg->trailing);

	for (i = 0; i < IRC_MAX_PARAMS; i++)
		free(msg->params[i]);
}

/** Prints an irc_server_msg_object. */
void irc_server_msg_print(irc_server_msg *msg)
{
	size_t i;

	printf("prefix:   %s\n", msg->prefix);
	printf("command:  %s\n", msg->command);

	if (msg->params)
		for (i = 0; msg->params[i] != NULL; i++)
			printf("param %d:  %s\n", i, msg->params[i]);

	printf("trailing: %s\n", msg->trailing);
}

/** Parses the irc server message from str and stores the result in irc_server_msg.
 *  The string must match the following pattern:
 *  [ ":" prefix SPACE ] command [ params ] [crlf]
 */
int irc_server_msg_parse(irc_server_msg *msg, const char *str)
{
	size_t i, j = 0, pnum = 0;
	char buf[IRC_MAX_BUFSIZ];
	int quit = 0;

	assert(str != NULL);
	assert(msg != NULL);

	enum states {start, space, prefix, command, param, trailing = 9} state = start;

	for (i = 0; ; i++) {
		switch (str[i]) {
		case ':':
			if (state == start) state = prefix;
			else if (state == command || state == param) state = trailing;
			break;
		case '\r':
			if (str[i+1] != '\n' || str[i+2] != '\0') return -1;
		case '\0':
			if (state != start && state != command && state != param && state != trailing) return -1;
			quit = 1;
		case ' ':
			switch(state) {
			case prefix:
				if ((msg->prefix = strdup(buf)) == NULL) return -1;
				j = 0;
				state = command;
				break;
			case command:
			case start:
				if ((msg->command = strdup(buf)) == NULL) return -1;
				j = 0;
				state = param;
				break;
			case param:
				if (pnum >= IRC_MAX_PARAMS) return -1;
				if ((msg->params[pnum++] = strdup(buf)) == NULL) return -1;
				j = 0;
				break;
			case trailing:
				if (quit) {
					if ((msg->trailing = strdup(buf)) == NULL) return -1;
				} else {
					buf[j++] = str[i];
					buf[j] = '\0';
				}
				break;
			default:
				return -1;
			}

			if (quit)
				return 0;
			break;
		default:
			buf[j++] = str[i];
			buf[j] = '\0';
			break;
		}
	}

	// we should never reach this point
	return -1;
}

/*
int main(void)
{
	irc_server_msg *msg;
	int ret;

	msg = irc_server_msg_create();

	ret = irc_server_msg_parse(msg, ":WiZ!jto@tolsun.oulu.fi NICK Kilroy WiZ blabla blubb :Foobar tralala");
	printf("ret: %d\n", ret);

	irc_server_msg_print(msg);
	irc_server_msg_free(msg);

	return 0;
}
*/
